package io.shuttle.mbe.api

import io.shuttle.mbe.api.types.StringOrObject
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.Value2Function
import io.shuttle.mbe.api.types.VoidFunction

interface Browser {
    interface Cast {
        enum class AutoJoinPolicy {
            custom_controller_scoped,
            tab_and_origin_scoped,
            origin_scoped,
            page_scoped
        }

        enum class DefaultActionPolicy {
            create_session,
            cast_this_tab
        }

        enum class Capability {
            video_out,
            audio_out,
            video_in,
            audio_in,
            multizone_group
        }

        enum class ErrorCode {
            cancel,
            timeout,
            api_not_initialized,
            invalid_parameter,
            extension_not_compatible,
            extension_missing,
            receiver_unavailable,
            session_error,
            channel_error,
            load_media_failed
        }

        enum class ReceiverAvailability {
            available,
            unavailable
        }

        enum class SenderPlatform {
            chrome,
            ios,
            android
        }

        enum class ReceiverType {
            cast,
            dial,
            hangout,
            custom
        }

        enum class ReceiverAction {
            cast,
            stop
        }

        enum class SessionStatus {
            connected,
            disconnected,
            stopped
        }

        var VERSION: List<Number>
        var isAvailable: Boolean

        fun initialize(
            apiConfig: ApiConfig,
            successCallback: VoidFunction,
            errorCallback: Value1Function<Error>
        )

        fun requestSession(
            successCallback: Value1Function<Session>,
            errorCallback: Value1Function<Error>,
            sessionRequest: SessionRequest,
            label: String?
        )

        fun requestSessionById(sessionId: String)

        fun addReceiverActionListener(listener: Value2Function<Receiver, ReceiverAction>)

        fun removeReceiverActionListener(listener: Value2Function<Receiver, ReceiverAction>)

        fun logMessage(message: String)

        fun setCustomReceivers(
            receivers: List<Receiver>,
            successCallback: VoidFunction,
            errorCallback: Value1Function<Error>
        )

        fun setReceiverDisplayStatus(
            receiver: Receiver,
            successCallback: VoidFunction,
            errorCallback: Value1Function<Error>
        )

        fun unescape(escaped: String): String

        data class ApiConfig(
            var sessionRequest: SessionRequest,
            var sessionListener: Value1Function<Session>,
            var receiverListener: Value1Function<ReceiverAvailability>,
            var autoJoinPolicy: AutoJoinPolicy? = null,
            var defaultActionPolicy: DefaultActionPolicy? = null
        )

        data class Error(
            var code: ErrorCode,
            var description: String? = null,
            var details: Any? = null
        )

        data class Image(
            var url: String,
            var width: Number? = null,
            var height: Number? = null
        )

        data class SenderApplication(
            var platform: SenderPlatform,
            var url: String? = null,
            var packageId: String? = null
        )

        data class SessionRequest(
            var appId: String,
            var capabilities: List<Capability>,
            var requestSessionTimeout: Number?,
            var language: String? = null
        )

        abstract class Session(
            var sessionId: String,
            var appId: String,
            var displayName: String,
            var appImages: List<Image>,
            var receiver: Receiver,
            var senderApps: List<SenderApplication> = emptyList(),
            var namespaces: List<Namespace> = emptyList(),
            var status: SessionStatus = SessionStatus.disconnected,
            var statusText: String?,
            var transportId: String = ""
        ) {
            abstract fun setReceiverVolumeLevel(
                newLevel: Number,
                successCallback: VoidFunction,
                errorCallback: Value1Function<Error>
            )

            abstract fun setReceiverMuted(
                muted: Boolean,
                successCallback: VoidFunction,
                errorCallback: Value1Function<Error>
            )

            abstract fun leave(successCallback: VoidFunction, errorCallback: Value1Function<Error>)
            abstract fun stop(successCallback: VoidFunction, errorCallback: Value1Function<Error>)
            abstract fun sendMessage(
                namespace: String,
                message: StringOrObject,
                successCallback: VoidFunction,
                errorCallback: Value1Function<Error>
            )

            abstract fun addUpdateListener(listener: Value1Function<Boolean>)
            abstract fun removeUpdateListener(listener: Value1Function<Boolean>)
            abstract fun addMessageListener(
                namespace: String,
                listener: Value2Function<String, String>
            )

            abstract fun removeMessageListener(
                namespace: String,
                listener: Value2Function<String, String>
            )

            abstract fun addMediaListener(listener: Value1Function<Media>)
            abstract fun removeMediaListener(listener: Value1Function<Media>)
            abstract fun loadMedia(
                loadRequest: Media.LoadRequest,
                successCallback: Value1Function<Media>,
                errorCallback: Value1Function<Error>
            )

            abstract fun queueLoad(
                queueLoadRequest: Media.QueueLoadRequest,
                successCallback: Value1Function<Media>,
                errorCallback: Value1Function<Error>
            )
        }


        data class Receiver(
            var label: String,
            var friendlyName: String,
            var capabilities: List<Capability>,
            var volume: Volume? = null,
            var receiverType: ReceiverType = ReceiverType.cast,
            var displayStatus: ReceiverDisplayStatus? = null
        )

        data class ReceiverDisplayStatus(
            var statusText: String,
            var appImages: List<Image>
        )

        data class Volume(
            var level: Number? = null,
            var muted: Number? = null
        )

        data class Namespace(var name: String)

        interface Media {
            var DEFAULT_MEDIA_RECEIVER_APP_ID: String

            enum class MediaCommand {
                pause,
                seek,
                stream_volume,
                stream_mute
            }

            enum class MetadataType {
                GENERIC,
                TV_SHOW,
                MOVIE,
                MUSIC_TRACK,
                PHOTO,
            }

            enum class PlayerState {
                IDLE,
                PLAYING,
                PAUSED,
                BUFFERING,
            }

            enum class ResumeState {
                PLAYBACK_START,
                PLAYBACK_PAUSE
            }

            enum class StreamType {
                BUFFERED,
                LIVE,
                OTHER
            }

            enum class IdleReason {
                CANCELLED,
                INTERRUPTED,
                FINISHED,
                ERROR
            }

            enum class RepeatMode {
                REPEAT_OFF,
                REPEAT_ALL,
                REPEAT_SINGLE,
                REPEAT_ALL_AND_SHUFFLE
            }

            data class QueueItem(
                var media: MediaInfo,
                var activeTrackIds: List<Number> = emptyList(),
                var autoplay: Boolean = false,
                var customData: Any? = null,
                var itemId: Number = 0,
                var preloadTime: Number = 0,
                var startTime: Number = 0
            )

            data class QueueLoadRequest(
                var items: List<QueueItem>,
                var customData: Any? = null,
                var repeatMode: RepeatMode = RepeatMode.REPEAT_ALL,
                var startIndex: Number = 0
            )

            data class QueueInsertItemsRequest(
                var items: List<QueueItem>,
                var customData: Any? = null,
                var insertBefore: Number = 0,
            )

            data class QueueRemoveItemsRequest(
                var items: List<Number>,
                var customData: Any? = null,
                var itemIds: List<Number> = emptyList()
            )

            data class QueueReorderItemsRequest(
                var itemIdsToRecorder: List<Number>,
                var customData: Any? = null,
                var insertBefore: Number = 0,
                var itemIds: List<Number> = emptyList()
            )

            data class QueueUpdateItemsRequest(
                var itemsToUpdate: List<QueueItem>,
                var customData: Any? = null
            )

            enum class TrackType {
                TEXT,
                AUDIO,
                VIDEO
            }

            enum class TextTrackType {
                SUBTITLES,
                CAPTIONS,
                DESCRIPTIONS,
                CHAPTERS,
                METADATA
            }

            enum class TextTrackEdgeType {
                NONE,
                OUTLINE,
                DROP_SHADOW,
                RAISED,
                DEPRESSED
            }

            enum class TextTrackWindowType {
                NONE,
                NORMAL,
                ROUNDED_CORNERS
            }

            enum class TextTrackFontGenericFamily {
                SANS_SERIF,
                MONOSPACED_SANS_SERIF,
                SERIF,
                MONOSPACED_SERIF,
                CASUAL,
                CURSIVE,
                SMALL_CAPITALS
            }

            enum class TextTrackFontStyle {
                NORMAL,
                BOLD,
                BOLD_ITALIC,
                ITALIC
            }

            data class GetStatusRequest(var customData: Any? = null)

            data class PauseRequest(var customData: Any? = null)

            data class PlayRequest(var customData: Any? = null)

            data class SeekRequest(
                var currentTime: Number = 0,
                var resumeState: ResumeState = ResumeState.PLAYBACK_START,
                var customData: Any? = null
            )

            data class StopRequest(var customData: Any? = null)

            data class VolumeRequest(var volume: Volume, var customData: Any? = null)

            data class LoadRequest(
                var media: MediaInfo,
                var activeTrackIds: List<Number> = emptyList(),
                var autoplay: Boolean = false,
                var currentTime: Number = 0,
                var customData: Any? = null,
                var playbackRate: Number? = null
            )

            data class EditTracksInfoRequest(
                var activeTrackIds: List<Number> = emptyList(),
                var textTrackStyle: TextTrackStyle? = null,
            )

            data class GenericMediaMetadata(
                var images: List<Image> = emptyList(),
                var metadataType: MetadataType = MetadataType.GENERIC,
                var releaseData: String = "",
                @Deprecated("releaseYear", replaceWith = ReplaceWith("releaseDate"))
                var releaseYear: Number = 0,
                var subtitle: String = "",
                var title: String = "",
                @Deprecated("type", replaceWith = ReplaceWith("metadataType"))
                var type: MetadataType = MetadataType.GENERIC
            )

            data class MovieMediaMetadata(
                var images: List<Image> = emptyList(),
                var metadataType: MetadataType = MetadataType.GENERIC,
                var releaseData: String = "",
                @Deprecated("releaseYear", replaceWith = ReplaceWith("releaseDate"))
                var releaseYear: Number = 0,
                var subtitle: String = "",
                var title: String = "",
                @Deprecated("type", replaceWith = ReplaceWith("metadataType"))
                var type: MetadataType = MetadataType.GENERIC
            )

            data class TvShowMediaMetadata(
                var metadataType: MetadataType = MetadataType.GENERIC,
                var seriesTitle: String = "",
                var title: String = "",
                var season: Number = 0,
                var episode: Number = 0,
                var images: List<Image> = emptyList(),
                var originalAirdate: String = "",
                @Deprecated("type", replaceWith = ReplaceWith("metadataType"))
                var type: MetadataType = MetadataType.GENERIC,
                @Deprecated("episodeTitle", replaceWith = ReplaceWith("title"))
                var episodeTitle: String = "",
                @Deprecated("seasonNumber", replaceWith = ReplaceWith("season"))
                var seasonNumber: Number = 0,
                @Deprecated("episodeNumber", replaceWith = ReplaceWith("episode"))
                var episodeNumber: Number = 0,
                @Deprecated("releaseYear", replaceWith = ReplaceWith("releaseDate"))
                var releaseYear: Number = 0
            )

            data class MusicTrackMediaMetadata(
                var metadataType: MetadataType = MetadataType.GENERIC,
                var albumName: String = "",
                var title: String = "",
                var albumArtist: String = "",
                var artist: String = "",
                var composer: String = "",
                var songName: String = "",
                var trackNumber: Number = 0,
                var discNumber: Number = 0,
                var images: List<Image> = emptyList(),
                var releaseData: String = "",
                @Deprecated("type", replaceWith = ReplaceWith("metadataType"))
                var type: MetadataType = MetadataType.GENERIC,
                @Deprecated("artistName", replaceWith = ReplaceWith("artist"))
                var artistName: String = "",
                @Deprecated("releaseYear", replaceWith = ReplaceWith("releaseDate"))
                var releaseYear: Number = 0
            )

            data class PhotoMediaMetadata(
                var metadataType: MetadataType = MetadataType.GENERIC,
                var title: String = "",
                var artist: String = "",
                var location: String = "",
                var images: List<Image> = emptyList(),
                var latitude: Number = 0,
                var longitude: Number = 0,
                var width: Number = 0,
                var height: Number = 0,
                var creationDateTime: String = "",
                @Deprecated("type", replaceWith = ReplaceWith("metadataType"))
                var type: MetadataType = MetadataType.GENERIC,
            )

            data class MediaInfo(
                var contentId: String,
                var contentType: String,
                var streamType: StreamType = StreamType.OTHER,
                var metadata: Any? = null,
                var duration: Number? = null,
                var tracks: List<Any/*FIXME*/>? = null,
                var textTrackStyle: Any/*FIXME*/? = null,
                var customData: Any? = null
            )

            abstract class Media(
                var sessionId: String,
                var mediaSessionId: Number
            ) {
                var activeTrackIds: List<Number>? = null
                var customData: Any? = null
                var idleReason: IdleReason? = null
                var items: List<QueueItem>? = null
                var liveSeekableRange: Any/*FIXME*/? = null
                var loadingItemId: Number? = null
                var media: MediaInfo? = null
                var playbackRate: Number = 0
                var playerState: PlayerState = PlayerState.IDLE
                var preloadedItemId: Number? = null
                var repeatMode: RepeatMode = RepeatMode.REPEAT_ALL
                var supportedMediaCommands: List<MediaCommand> = emptyList()
                var volume: Volume? = null

                @Deprecated("currentTime", replaceWith = ReplaceWith("getEstimatedTime"))
                var currentTime: Number = 0

                abstract fun getStatus(
                    getStatusRequest: GetStatusRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun play(
                    playRequest: PlayRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun pause(
                    pauseRequest: Any/*FIXME: */,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun seek(
                    seekRequest: SeekRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun stop(
                    stopRequest: StopRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun setVolume(
                    volumeRequest: VolumeRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun editTracksInfo(
                    editTracksInfoRequest: EditTracksInfoRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun supportsCommand(command: MediaCommand): Boolean

                abstract fun addUpdateListener(listener: Value1Function<Boolean>)

                abstract fun removeUpdateListener(listener: Value1Function<Boolean>)

                @Deprecated(
                    "getEstimatedTime",
                    replaceWith = ReplaceWith("Uses currentTime member to compute estimated time")
                )
                abstract fun getEstimatedTime(): Number

                abstract fun queueAppendItem(
                    item: QueueItem,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueInsertItems(
                    queueInsertItemsRequest: QueueInsertItemsRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueJumpToItem(
                    itemId: Number,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueMoveItemToNewIndex(
                    itemId: Number,
                    newIndex: Number,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueNext(
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queuePrev(
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueRemoveItem(
                    itemId: Number,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueReorderItems(
                    queueReorderItemsRequest: QueueReorderItemsRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueSetRepeatMode(
                    repeatMode: RepeatMode,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )

                abstract fun queueUpdateItems(
                    queueUpdateItemsRequest: QueueUpdateItemsRequest,
                    successCallback: VoidFunction,
                    errorCallback: Value1Function<Error>
                )
            }

            abstract class Track(var trackId: Number, var type: TrackType) {
                var trackContentId: String = ""
                var trackContentType: String = ""
                var name: String = ""
                var language: String = ""
                var subtype: TextTrackType = TextTrackType.METADATA
                var customData: Any? = null
            }

            data class TextTrackStyle(
                var forgroundColor: String = "",
                var backgroundColor: String = "",
                var edgeType: TextTrackEdgeType = TextTrackEdgeType.NONE,
                var edgeColor: String = "",
                var windowType: TextTrackWindowType = TextTrackWindowType.NONE,
                var windowColor: String = "",
                var windowRoundedCornerRadius: Number = 0,
                var fontScale: Number = 0,
                var fontFamily: String = "",
                var fontGenericFamily: TextTrackFontGenericFamily =
                    TextTrackFontGenericFamily.SANS_SERIF,
                var fontStyle: TextTrackFontStyle = TextTrackFontStyle.NORMAL,
                var customData: Any? = null
            )

            abstract class LiveSeekableRange(
                var start: Number? = null,
                var end: Number? = null,
                var isMovingWindow: Boolean? = false,
                var isLiveDone: Boolean? = null
            )
        }

        interface Timeout {
            var load: Number
            var getStatus: Number
            var play: Number
            var pause: Number
            var seek: Number
            var stop: Number
            var setVolume: Number
            var editTracksInfo: Number
            var queueInsert: Number
            var queueLoad: Number
            var queueRemove: Number
            var queueReorder: Number
            var queueUpdate: Number
        }

    }
}